424. 替换后的最长重复字符

424. 替换后的最长重复字符

Similar Question

leading to the advanced question

Solution Tips

方案一: 滑动窗口

/**
 * @param {string} s
 * @param {number} k
 * @return {number}
 */
var characterReplacement = function(s, k) {
    // 窗口内去确认主字符, 通过贪心思想, 认为数量最多的是主字符
    // 因为主字符可能随着窗口的扩大而切换, 因此需要记录每个字符出现的个数, 并计算非主字符的总数
    // 保证非主字符的总数小于等于 k, 此时主字符的重复子串最长
    let left = 0;
    let right = 0;
    const map = {};
    let max = 0;
    let maxChar = '';
    let sum = 0;
    let rest = 0;

    let maxLen = 0;

    while (right < s.length) {
        const char = s[right];
        map[char] = (map[char] || 0) + 1;
        // 计算主字符数和非主字符数
        // 因为字符是一个个增加的, 所以只需要维护一个 max 和 sum 即可
        // 当新的字符超过了 max 时, 同样是 max++ 和 sum++
        sum++;
        if (map[char] > max) {
            max = map[char];
            maxChar = char;
        };
        rest = sum - max;
        if (rest <= k) {
            // 这个窗口的极限到了, 更新长度
            maxLen = Math.max(maxLen, right - left + 1);
        }

        if (rest > k) {
            // 调整左侧的窗口大小
            const leftChar = s[left];
            --map[leftChar];
            sum--;
            // max 好像没办法更新... 其实 max 只要能--就行, rest 可以直接算出来
            // maxChar 发生了变化好像没办法计算出来
            // 所以这里还是乖乖走 map 解析吧
            const [newMaxChar, newMax] = getMax(map);
            max = newMax;
            maxChar = newMaxChar;
            left++;
        }

        right++;
    }

    return maxLen;

    function getMax(map) {
        return Object.entries(map).reduce((max, [key, value]) => value > max[1]? [key, value] : max, ['', 0])
    }
};

方案二: 官解 Case 优化

实际上, 窗口的大小再达到最大之后会不会再缩小了, 因为假如后面的都是不符合条件的 right 每增大一位, left 就得马上缩小一位

所以官解最后返回了 right - left

类似的原因, 导致 maxChar 也不需要在 left++ 的时候更新, 因为如果新的 char 没有超过之前的 maxChar 最终返回值是不会更新的.

因此有了官解这个更加简洁的解法:

var characterReplacement = function(s, k) {
    const num = new Array(26).fill(0);
    const n = s.length;
    let maxn = 0, left = 0, right = 0;

    while (right < n) {
        num[s[right].charCodeAt() - 'A'.charCodeAt()]++;
        maxn = Math.max(maxn, num[s[right].charCodeAt() - 'A'.charCodeAt()])
        if (right - left + 1 - maxn > k) {
            num[s[left].charCodeAt() - 'A'.charCodeAt()]--;
            left++;
        }
        right++;
    }
    return right - left;
};